home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <netdb.h>
- #include "netconf.h"
- #include "../misc/misc.h"
- #include "../xconf/xconf.h"
- #include "netconf.m"
-
- static NETCONF_HELP_FILE help_hosts ("hosts");
- NETCONF_HELP_FILE help_networks ("networks");
- static CONFIG_FILE f_hosts (ETC_HOSTS,help_hosts,CONFIGF_MANAGED);
-
- void *operator new(size_t size)
- {
- void *ret = malloc(size);
- if (ret == NULL){
- xconf_error (MSG_U(E_OUTOFMEMORY,"Out of memory\n"));
- exit (-1);
- }
- return ret;
- }
-
-
- PUBLIC void HOST::set (const char *buf)
- {
- /* #Specification: /etc/hosts / format
- A hosts file has the following format
-
- # comment
- ip_number hostname [ alias ... ] [ # comment ]
-
- When we read /etc/hosts, we split the line in four parts, being
- the ip_numer, the first name, all the alias and the comment.
-
- Further, when collecting the comment, we try to keep even
- the space between the last data and the #.
-
- We hope to be able to edit normal /etc/hosts file and
- rewrite it mostly respecting the original format.
-
- Blank line are also remembered as comment.
- */
- is_valid = 1;
- freeall();
- const char *pt = str_skip(buf);
- if (isdigit(*pt)){
- // First copy the ip number
- char tmp[200];
- char *ptd = tmp;
- while (*pt > ' ') *ptd++ = *pt++;
- *ptd = '\0';
- ip_num.setfrom(tmp);
- pt = str_skip (pt);
- if (*pt > ' '){
- ptd = tmp;
- while (*pt > ' ') *ptd++ = *pt++;
- *ptd = '\0';
- name1.setfrom (tmp);
- const char *endname1 = pt;
- pt = str_skip (pt);
- if (*pt == '#'){
- comment.setfrom (endname1);
- }else if (*pt > ' '){
- const char *begother = pt;
- while (*pt != '#' && *pt != '\0') pt++;
- if (*pt == '\0'){
- others.setfrom (begother);
- }else{
- while (isspace(pt[-1])) pt--;
- int lenother = (int)(pt-begother);
- memcpy (tmp,begother,lenother);
- tmp[lenother] = '\0';
- others.setfrom (tmp);
- comment.setfrom (pt);
- }
- }
- }else{
- is_valid = 0;
- }
- }else if (*pt == '#'){
- comment.setfrom (buf);
- }else if (pt[0] != '\0'){
- // Anything else than a blank link is an error at this point
- is_valid = 0;
- }
- }
- /*
- Setup and parse a record from /etc/hosts
- */
- PUBLIC HOST::HOST(const char *buf)
- {
- set (buf);
- }
- PUBLIC HOST::HOST(
- const char *_ip_num,
- const char *_name1,
- const char *_others,
- const char *_comment)
- {
- ip_num.setfrom (_ip_num);
- name1.setfrom(_name1);
- others.setfrom (_others);
- comment.setfrom (_comment);
- }
- PUBLIC HOST::HOST()
- {
- }
- /*
- Cleanup of the HOST, same as destructor
- */
- PRIVATE void HOST::freeall()
- {
- ip_num.setfrom (NULL);
- name1.setfrom(NULL);
- others.setfrom(NULL);
- comment.setfrom(NULL);
- }
- PUBLIC VIRTUAL HOST::~HOST()
- {
- }
-
- /*
- Return the principal name of a host
- */
- PUBLIC const char *HOST::getname1() const
- {
- return name1.get();
- }
- /*
- Record the principal name of a host
- */
- PUBLIC void HOST::setname1(const char *_name1)
- {
- name1.setfrom (_name1);
- }
- /*
- Return != 0 if this entry is only a comment, not a host definition.
- */
- PUBLIC int HOST::iscomment() const
- {
- return ip_num.is_empty();
- }
- /*
- Return the comment associated with an entry.
- */
- PUBLIC const char *HOST::getcomment() const
- {
- return comment.get();
- }
- /*
- Record the comment associate with a host.
- */
- PUBLIC void HOST::setcomment(const char *_comment)
- {
- comment.setfrom (_comment);
- }
- /*
- Return the alternatives names for a host (maybe more than one) as
- a single string or "" is none.
- */
- PUBLIC const char *HOST::getothers() const
- {
- return others.get();
- }
- /*
- Record the others names of a host
- */
- PUBLIC void HOST::setothers(const char *_others)
- {
- others.setfrom (_others);
- }
-
- /*
- Return the IP number of a host.
- */
- PUBLIC const char *HOST::getipnum() const
- {
- return ip_num.get();
- }
- /*
- Record the IP adress of a host.
- */
- PUBLIC void HOST::setipnum(const char *_ipnum)
- {
- ip_num.setfrom (_ipnum);
- }
- /*
- Output one HOST record in ascii
- */
- PUBLIC VIRTUAL void HOST::print (FILE *fout) const
- {
- if (!ip_num.is_empty()) fprintf (fout,"%s",ip_num.get());
- if (!name1.is_empty()) fprintf (fout,"\t%s",name1.get());
- if (!others.is_empty()) fprintf (fout,"\t%s",others.get());
- if (!comment.is_empty()) fprintf (fout,"%s",comment.get());
- fputc ('\n',fout);
- }
-
- /*
- Return !- 0 if this is a special entry of /etc/hosts.
- This entry is special because it must exist for this program
- to work (and many program). The loopback and the entry of the
- current machine.
- */
- PUBLIC VIRTUAL int HOST::is_special() const
- {
- return ip_num.is_empty()
- || ip_num.cmp("127.0.0.1")==0;
- }
-
- /*
- Free and allocate conditionnally.
- Return the new allocated pointer or NULL.
- */
- char *replaceif(char *last,const char *newval)
- {
- free (last);
- char *ret = NULL;
- if (newval[0] != '\0') ret = strdup (newval);
- return ret;
- }
- /*
- Edit a host definition.
- Return -1 if the input is cancelled
- Return 0 if it is accepted
- Return 1 if the user request deletion of this record.
- */
- PUBLIC VIRTUAL int HOST::edit (HELP_FILE &helpfile)
- {
- int ret = -1;
- DIALOG dia;
- dia.newf_str (MSG_R(F_PRIMNAME),name1);
- dia.newf_str (MSG_R(F_ALIASES),others);
- dia.newf_str (MSG_U(F_IPNUM,"IP number"),ip_num);
- dia.newf_str (MSG_R(F_COMMENT),comment);
- int nofield = 0;
- while (1){
- int code = dia.edit (MSG_U(T_HOSTNETDEF,"host/network definition")
- ,NULL
- ,helpfile
- ,nofield,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
- if (code == MENU_CANCEL || code == MENU_ESCAPE){
- break;
- }else if (code == MENU_DEL){
- ret = 1;
- break;
- }else if (code ==MENU_ACCEPT){
- if (!device_validip(ip_num.get(),false)){
- xconf_error (MSG_U(E_IVLIPNUM,"Invalid IP number"));
- }else{
- ret = 0;
- break;
- }
- }
- }
- if (ret != 0) dia.restore();
- return ret;
- }
-
- PUBLIC HOSTS::HOSTS()
- {
- cfgf = &f_hosts;
- }
-
- PUBLIC VIRTUAL HOST *HOSTS::newhost (
- const char *_ip_num,
- const char *_name1,
- const char *_others,
- const char *_comment)
- {
- return new HOST (_ip_num,_name1,_others,_comment);
- }
- PUBLIC VIRTUAL HOST *HOSTS::newhost (const char *buf)
- {
- return new HOST (buf);
- }
- /*
- Add a line to the in memory hosts table
- The line may be a comment or invalid
- */
- PUBLIC VIRTUAL void HOSTS::add (const char *buf)
- {
- HOST *pt = newhost(buf);
- add (pt);
- }
- /*
- Add a line to the in memory hosts table
- */
- PUBLIC VIRTUAL void HOSTS::add (
- const char *_ip_num,
- const char *_name1,
- const char *_others,
- const char *_comment)
- {
- HOST *pt = newhost (_ip_num,_name1,_others,_comment);
- add (pt);
- }
- /*
- Add one item to the in memory hosts table
- */
- PUBLIC void HOSTS::add (HOST *pt)
- {
- grow();
- tb[nb++] = pt;
- }
-
- /*
- Read and parse a hosts file (normally /etc/hosts).
- Return -1 if any error.
- */
- PUBLIC int HOSTS::read ()
- {
- int ret = -1;
- FILE *fin = cfgf->fopen ("r");
- if (fin != NULL){
- char buf[500];
- ret = 0;
- while (fgets_cont(buf,sizeof(buf)-1,fin) != -1){
- add (buf);
- }
- fclose (fin);
- }
- return ret;
- }
- /*
- Write a hosts file (normally /etc/hosts).
- Return -1 if any error.
- */
- PUBLIC int HOSTS::write () const
- {
- int ret = -1;
- FILE *fout = cfgf->fopen ("w");
- if (fout != NULL){
- ret = 0;
- for (int i=0; i<nb; i++) getitem(i)->print (fout);
- fclose (fout);
- }
- return ret;
- }
- /*
- Return one entry of the hosts file.
- Returne NULL if the entry is out of range.
- */
- PUBLIC HOST *HOSTS::getitem(int no) const
- {
- return (HOST*)ARRAY::getitem(no);
- }
-
- /*
- Lookup a host name in the "other name" string.
- Return != 0 if found.
- */
- int host_lookupother (const char *others, const char *name)
- {
- int ret = 0;
- while (1){
- char buf[200];
- others = str_skip(others);
- others = str_copyword (buf,others);
- if (buf[0] == '\0') break;
- if (strcmp(buf,name)==0){
- ret = 1;
- break;
- }
- }
- return ret;
- }
-
- /*
- Find a name in the in memory host table.
- Returne NULL or the entry.
- */
- PUBLIC HOST *HOSTS::getitem(const char *name) const
- {
- HOST *ret = NULL;
- if (name[0] != '\0'){
- for (int i=0; i<nb; i++){
- HOST *pt = getitem(i);
- if (stricmp(name,pt->getname1())==0
- || host_lookupother(pt->getothers()
- ,name)){
- ret = pt;
- break;
- }
- }
- }
- return ret;
- }
- /*
- Sort host by name
- */
- static int cmp_host_by_name (const void *p1, const void *p2)
- {
- HOST *h1 = *(HOST**)p1;
- HOST *h2 = *(HOST**)p2;
- return strcmp(h1->getname1(),h2->getname1());
- }
- /*
- Edit the file /etc/hosts or /etc/networks
- */
- PUBLIC int HOSTS::edit(
- const char *title,
- HELP_FILE &helpfile)
- {
- int ret = -1;
- int choice=0;
- while (1){
- int nbh = getnb(); // Number of entry including comments
- HOST **tbsort = new HOST *[nbh];
- if (tbsort != NULL){
- // Extracting hosts only, no comments
- // Hide information about this host
- THISHOST thost;
- const char *thishost_ip = thost.getipnum(0);
- int nb=0;
- for (int i=0; i<nbh; i++){
- HOST *pt = getitem(i);
- if (!pt->iscomment() && !pt->is_special()
- && strcmp(pt->getipnum(),thishost_ip)!=0){
- tbsort[nb++] = pt;
- }
- }
- qsort (tbsort,nb,sizeof(HOST *),cmp_host_by_name);
- // Format all the entries in a menu.
- // The first entry is dummy. It allows addition to the list
- const char **menuopt = new const char *[(nb+2)*2+1];
- int ii=0;
- for (i=0; i<nb; i++,ii+=2){
- HOST *pth = tbsort[i];
- menuopt[ii] = (char*)pth->getipnum();
- char buf[300];
- sprintf (buf,"%s %s %s",pth->getname1(),pth->getothers()
- ,pth->getcomment());
- buf[50] = '\0';
- menuopt[ii+1] = strdup(buf);
- }
- menuopt[ii] = NULL;
- //char save_what[100];
- //sprintf (save_what,MSG_U(I_UPDHOSTS,"To update %s")
- // ,cfgf->getpath());
- MENU_STATUS code = xconf_menu (title
- ,MSG_U(I_HOSTSDEF
- ,"Select a host/network definition to modify")
- ,helpfile
- ,NULL
- ,NULL
- ,NULL
- ,MSG_U(I_ADDDEF,"to add a new definition")
- ,menuopt,choice);
- if (code == MENU_ESCAPE || code == MENU_QUIT){
- break;
- }else if (code == MENU_ADD){
- HOST *hst = newhost("");
- if (hst != NULL){
- if (hst->edit(helpfile)==0){
- add(hst);
- write ();
- }else{
- delete hst;
- }
- }
- }else if(nb>0){
- // Edit one hosts
- HOST *hst = tbsort[choice];
- int ok = hst->edit(helpfile);
- if (ok != -1){
- if (ok == 1) remove_del (hst);
- write();
- }
- }
- for (i=0; i<nb; i++) free ((char*)(menuopt[i*2+1]));
- delete [] menuopt;
- }
- }
- return ret;
- }
- /*
- Edit the file /etc/hosts
- */
- void netconf_edithosts()
- {
- HOSTS hosts;
- if (hosts.read () != -1){
- hosts.edit(ETC_HOSTS,help_hosts);
- }
- }
- /*
- Edit the file /etc/networks
- */
- void netconf_editnet()
- {
- NETWORKS nets;
- if (nets.read () != -1){
- nets.edit(ETC_NETWORKS,help_networks);
- }
- }
-
- #ifdef TEST
-
- int main (int , char *[])
- {
- HOSTS hosts;
- hosts.read ();
- hosts.write ();
- return 0;
- }
- #endif
-
-